#include <types.h>
#include <sys_config.h>

#include <retcode.h>
#include <api/libc/string.h>
#include <api/libc/printf.h>
#include <osal/osal.h>
#include <hld/hld_dev.h>
#include <hld/dis/vpo.h>
#include <hld/decv/vdec_driver.h>
#include <hld/decv/decv.h>
#include <hld/ge/ge.h>
#include <hld/osd/osddrv.h>

#include <api/libmp/pe.h>
#include <api/libmp/gif.h>
#include "../../image_engine.h"
#include "../../plugin.h"
#include <api/libfs2/stdio.h>
//#include "gif.h"

//#define AD_GIF_DEBUG

#ifdef AD_GIF_DEBUG
#define AD_GIF_PRINTF	libc_printf
#else
#define AD_GIF_PRINTF(...)	do{}while(0)
#endif

//extern UINT8 alpha_value_flag;

#define ENABLE_PE_CACHE
#ifdef 	ENABLE_PE_CACHE
#define	GIF_BLOCK_SIZE		(320 * 1024)
#define 	GIF_CACHE_SIZE		(GIF_BLOCK_SIZE * 2)
#define GIF_BIT_SIZE		0x8000*3
#define GIF_DEC_SIZE		0x1D0000*3//0xEF600*3 max_width * max_height * out_fomat(osd: 8bit, other: present osd color format)
static int gif_cache_id = -1;
static UINT8 *gif_cache_buffer;
#endif

static struct gif_dec_par par;

static struct gif_instance *gif = NULL;
static gif_file fh;
extern UINT16 tran_use_number;
extern int clean_flag;
//extern UINT8 alpha_value_flag;

struct jpeg_file
{
	imagedec_id				id; 			//image id for decoder
	Imagedec_Init_Config 	init_conf;		//configurefor decoder

	FILE					*fp;			//file pointer for JPEG
	unsigned long			task_terminated;
	mp_callback_func		mp_cb;			//callback function for mp
	OSAL_ID					lock;
};

static struct jpeg_file jpeg_file;
static struct gif_cfg gif_cfg;

static int gif_read_data(UINT32 fh,BYTE *buf, UINT32 size)
{
	int ret = 0;

#ifdef ENABLE_PE_CACHE
	if(gif_cache_id >= 0)
	{
		ret = pe_cache_read(gif_cache_id, buf, size, 0xFFFFFFFF);
		return ret;
	}
#endif

#ifndef ENABLE_PE_CACHE
	FILE *fp =  (FILE*)fh;
	int byte_read;

	if(fp == NULL)
	{
		return -1;
	}

	byte_read = fread(buf, size, 1, fp);

	return ((byte_read < 0) ? 0 : byte_read) ;
#endif

}

static int gif_seek_data(UINT32 fh,long offset, UINT32 origin)
{
#ifdef ENABLE_PE_CACHE
    if(gif_cache_id >= 0)
    {
        pe_cache_seek(gif_cache_id, (off_t)offset, origin);
        return 0;
    }
#endif

#ifndef ENABLE_PE_CACHE
	FILE *fp = (FILE*)fh;

	if(fp == NULL)
	{
		return -1;
	}

	fseek(fp, (off_t)offset, origin);
#endif
	return 0;
}

static int gif_tell_pos(UINT32 fh)
{
    /*
	FILE *fp = (FILE*)fh;

	if(fp == NULL)
	{
		return -1;
	}

	return ftell(fp);
	*/
	return 0;

}


static UINT32 jpeg_process(void *value)
{
	unsigned long process = *(unsigned long*)value;
	unsigned long err = process >> 24;

	process = (process * 100) >> 16;

	if(process > 100) process = 100;

	osal_mutex_lock(jpeg_file.lock, TMO_FEVR);
	if(jpeg_file.mp_cb)
	{
		if(err == 0)
			jpeg_file.mp_cb(MP_IMAGE_DECODE_PROCESS, process);
		else
			jpeg_file.mp_cb(MP_IMAGE_DECODER_ERROR, err);
	}
	osal_mutex_unlock(jpeg_file.lock);

	return 0;
}

/*
static int gif_init(struct pe_image_cfg *pe_image_cfg)
{
	struct gif_cfg init;

	MEMSET((void *)&init,0,sizeof(struct gif_cfg));
	MEMSET((void *)&par,0,sizeof(struct gif_dec_par));

	init.bit_buf_start = (UINT8 *)(GIF_BIT_BUF & ~(7<<28));
	init.bit_buf_size = GIF_BIT_SIZE;
	init.dec_buf_start = (UINT8 *)(GIF_DEC_BUF & ~(7<<28));
	init.dec_buf_size = GIF_DEC_SIZE;

	init.fread_callback = gif_read_data;
	init.fseek_callback = gif_seek_data;
	init.ftell_callback = gif_tell_pos;
	//jpg_file_init(JPEG_START,JPEG_SIZE);
	gif_init(&init);
}
*/
#ifdef  DUAL_ENABLE
static void osd_output_init(void)
{
    struct osd_device *osd_dev;
    UINT32 region_id =0;
    UINT32 trans_color;
    struct OSDRect region_rect;
    struct OSDPara OpenPara;
    UINT8 *p_pallette;

    region_rect.uLeft = 0;
	region_rect.uTop = 0;
	region_rect.uWidth = 800;//OSD_MAX_WIDTH;//608;
	region_rect.uHeight = 500;//OSD_MAX_HEIGHT;//430;

    OpenPara.eMode = OSD_256_COLOR;
    OpenPara.uGAlpha = 0x0f;
    OpenPara.uGAlphaEnable = 0;
    OpenPara.uPalletteSel = 0;
    osd_dev = (struct osd_device *)dev_get_by_id(HLD_DEV_TYPE_OSD, 0);
    OSDDrv_Open((HANDLE)osd_dev, &OpenPara);
    osal_task_sleep(20);
    //trans_color = OSD_GetTransColor(OpenPara.eMode,FALSE);
	OSDDrv_IoCtl((HANDLE)osd_dev, OSD_IO_SET_TRANS_COLOR, 0x00);
	OSDDrv_CreateRegion((HANDLE)osd_dev, region_id, &region_rect, NULL);
    //p_pallette = OSD_GetRscPallette(0x4080 | 0);
	//OSD_SetPallette(p_pallette,256);

    //OSDDrv_RegionFill((HANDLE)osd_dev,region_id,&region_rect,0xff);
    //OSDDrv_ShowOnOff((HANDLE)osd_dev, TRUE);
}
#endif

static void pic_gif_init(void)
{

	gif_init(&gif_cfg);
	//gif_list_init();
	gif = gif_open();
}

static int gif_initial(struct pe_image_cfg *pe_image_cfg)
{
#ifdef ENABLE_PE_CACHE
	gif_cache_buffer = (unsigned char *)(((unsigned long)pe_image_cfg->decoder_buf) & 0xfffffff0);
	gif_cache_buffer = (unsigned char *)(((unsigned long)gif_cache_buffer & 0x0fffffff) | 0x80000000);
#endif
    MEMSET((void *)&gif_cfg,0,sizeof(struct gif_cfg));
	gif_cfg.bit_buf_start = pe_image_cfg->decoder_buf + GIF_CACHE_SIZE;
	gif_cfg.bit_buf_size = GIF_BIT_SIZE;
	gif_cfg.dec_buf_start = gif_cfg.bit_buf_start + GIF_BIT_SIZE;
	gif_cfg.dec_buf_size = GIF_DEC_SIZE;

	gif_cfg.fread_callback = gif_read_data;
	gif_cfg.fseek_callback = gif_seek_data;
	gif_cfg.ftell_callback = gif_tell_pos;
	gif_cfg.max_width = 1280;//800; //400;
	gif_cfg.max_height = 720;//600; //300;

}

/*static int jpeg_cleanup(void)
{
	if(jpeg_file.id > 0)
	{
		imagedec_release(jpeg_file.id);
		jpeg_file.id = 0;
		osal_mutex_delete(jpeg_file.lock);
	}

}
*/

static int gif_is_our_file(char *filename)
{
	char *ext;
#ifndef	 _USE_32M_MEM_
	ext = strrchr(filename, '.');
	if (ext)
	{
		if((!strncasecmp(ext, ".gif", 4)) )
		{
			return TRUE;
		}
	}
#endif
	return FALSE;
}

enum Output_Frame_Ret_Code imagedec_mp_request(void *dev, void *pinfo);
BOOL imagedec_mp_release(void *dev,UINT8 utop_idx,UINT8 frm_array_idx);

static UINT8 gif_show_on;  //1,gif is to been showed ; 0 gif has been be showed
static UINT8 first_time = 0;  //0,the first time of showing the gifs

static INT32 pic_gif_draw(gif_file fh, struct OSDRect  *rect, BOOL animation)
{
	struct gif_dec_par par;
	struct ge_device* ge_dev;

	ge_dev = (struct ge_device *)dev_get_by_id(HLD_DEV_TYPE_GE, 0);
	if (ge_dev == NULL)
	{
		AD_GIF_PRINTF("%s() ge device find failed!\n", __FUNCTION__);
		return !SUCCESS;
	}

#ifdef  DUAL_ENABLE
    struct osd_device* osd_dev;

    osd_dev = (struct ge_device *)dev_get_by_id(HLD_DEV_TYPE_OSD, 0);
    if (osd_dev == NULL)
	{
		AD_GIF_PRINTF("%s() osd device find failed!\n", __FUNCTION__);
		return !SUCCESS;
	}
#endif

	//if (SUCCESS != ad_gif_file_add(fh))
	//	return !SUCCESS;

	//gif_file_init(fh, file, file_len);

	if (animation)
		gif_io_ctrl(gif, GIF_IO_CMD_DEC_FIRST_PIC, GIF_FALSE);
	else
		gif_io_ctrl(gif, GIF_IO_CMD_DEC_FIRST_PIC, GIF_TRUE);

	MEMSET((void *)&par, 0, sizeof(struct gif_dec_par));
	par.in_par.file = fh;
	par.in_par.fread_callback = gif_read_data;
	par.in_par.fseek_callback = gif_seek_data;
	par.in_par.ftell_callback = gif_tell_pos;

	par.out_par.dev = (gif_ge_dev)ge_dev;
#ifdef  DUAL_ENABLE
    par.out_par.dev = (gif_ge_dev)osd_dev;
#endif
	par.out_par.handle = 0;//(gif_surface_handle)ad_get_ge_surface(AD_DST_SURFACE);
	par.out_par.region = 0;
	par.out_par.pos.x = rect->uLeft;
	par.out_par.pos.y = rect->uTop;
	par.out_par.area.x = par.out_par.area.y = 0;
	par.out_par.area.w = rect->uWidth;
	par.out_par.area.h = rect->uHeight;

	gif_dec(gif, &par);

	return SUCCESS;
}

static int gif_draw(char *filename, void *args)
{
	struct OSDRect rect;
/*
#ifdef ENABLE_PE_CACHE
	if(gif_cache_id >= 0) pe_cache_close(gif_cache_id);
	gif_cache_id = -1;
#endif
*/
#ifdef	 _USE_32M_MEM_
	return FALSE;
#endif
	char *ext;

	ext = strrchr(filename, '.');
	if (ext)
	{
		if((strncasecmp(ext, ".gif", 4)) )
		{
			return FALSE;
		}
	}

#ifndef ENABLE_PE_CACHE
	FILE *fp = fopen(filename, "rb");
	if(fp == NULL)
	{
		return -1;
	}
	fh = (gif_file)fp;
#endif

#ifdef ENABLE_PE_CACHE
	AD_GIF_PRINTF("filename: %s\n", filename);
	gif_cache_id = pe_cache_open(filename, gif_cache_buffer, GIF_CACHE_SIZE, GIF_BLOCK_SIZE);
	AD_GIF_PRINTF("filename: %s,   pe_cache_id: %d\n", filename, gif_cache_id);
	if (gif_cache_id < 0)
		return -1;
#endif

#ifdef ENABLE_PE_CACHE
	fh = 1;			// avoid imagedec_decode return FALSE without FS API
#endif

	rect.uLeft = 0;//100;
	rect.uTop = 0;//40;
	rect.uWidth = 1280;//800;
	rect.uHeight = 720;//600;

	pic_gif_init();

	pic_gif_draw(fh,  &rect, TRUE);
/*
#ifdef ENABLE_PE_CACHE
	pe_cache_close(gif_cache_id);
	gif_cache_id = -1;
#endif

#ifndef ENABLE_PE_CACHE
	fclose(fp);
	fp = NULL;
#endif
	*/

	return 0;
}

static int gif_abort(void)
{
    struct osd_device *osd_dev;
    struct OSDRect rect;
	/*
	if(jpeg_file.id > 0)
	{
		osal_mutex_lock(jpeg_file.lock, TMO_FEVR);
		jpeg_file.mp_cb = NULL;
		osal_mutex_unlock(jpeg_file.lock);

		imagedec_stop(jpeg_file.id);

		while(jpeg_file.task_terminated == 1)
		{
			osal_task_sleep(10);
		}
	}
	*/
	//gif_file fh;

#ifdef ENABLE_PE_CACHE
	if(gif_cache_id >= 0) pe_cache_close(gif_cache_id);
	gif_cache_id = -1;
#endif

#ifdef ENABLE_PE_CACHE
	fh = 1;
#endif

	if (gif == NULL)
		return 0;

	gif_stop(gif, fh);

	gif_close(gif);
#ifndef  DUAL_ENABLE
    if(clean_flag)
    {
    osd_dev = (struct osd_device *)dev_get_by_id(HLD_DEV_TYPE_OSD, 0);
    OSDDrv_GetRegionPos((HANDLE)osd_dev,0,&rect);
    rect.uLeft = rect.uTop = 0;
    OSDDrv_RegionFill((HANDLE)osd_dev,0,&rect,0xff);
    }
#endif
    //OSD_ClearScreen();
    //alpha_value_flag = 0;
#ifdef  DUAL_ENABLE
    if(clean_flag)
    {
    osd_dev = (struct osd_device *)dev_get_by_id(HLD_DEV_TYPE_OSD, 0);
    OSDDrv_ShowOnOff((HANDLE)osd_dev,FALSE);
    OSDDrv_Close((HANDLE)osd_dev);
    tran_use_number = 256;
    }

#endif

	gif = NULL;
}


ImagePlugin gif_plugin =
{
	.handle = 0,
	.filename = NULL,
	.description = NULL,
	.init = gif_initial,
	.about = NULL,
	.configure = NULL,
	.is_our_file = gif_is_our_file,
	.decode = gif_draw,
	.show = NULL,//jpeg_show,
	.abort =gif_abort,//jpeg_abort,
	.cleanup = NULL,//jpeg_cleanup,
	.get_info = NULL,//jpeg_get_info,
	.zoom = NULL,//jpeg_zoom,
};


